#include "linesegment.h"
#include "line.h"
#include <QDebug>
#include "utilities.h"

GeometryUtilities::LineSegment::LineSegment() {}

GeometryUtilities::LineSegment::LineSegment(const GeometryUtilities::Point& begin,
                                            const GeometryUtilities::Point& end)
: mBegin(begin), mEnd(end) {}

QLineF GeometryUtilities::LineSegment::toQLineF() const
{
  return QLineF(mBegin, mEnd);
}

const GeometryUtilities::Point& GeometryUtilities::LineSegment::begin() const
{
  return mBegin;
}

GeometryUtilities::Point& GeometryUtilities::LineSegment::begin()
{
  return mBegin;
}

const GeometryUtilities::Point& GeometryUtilities::LineSegment::end() const
{
  return mEnd;
}

GeometryUtilities::Point& GeometryUtilities::LineSegment::end()
{
  return mEnd;
}

bool GeometryUtilities::LineSegment::isPointOn
(const GeometryUtilities::Point& p) const
{
  GeometryUtilities::Line l(mBegin, mEnd);
  qreal bx = mBegin.x(), ex = mEnd.x(),
        by = mBegin.y(), ey = mEnd.y();
  if (!l.isVertical()) // For non vertical
  {                                   
    if (Utilities::floatEquality(p.y(), p.x()*l.slope()+l.yIntercept()))
      if ((bx <= p.x() && p.x() <= ex) || (ex <= p.x() && p.x() <= bx))
        if ((by <= p.y() && p.y() <= ey) || (ey <= p.y() && p.y() <= by))
          return true;
    return false;
  }
  else
  {
    if ((by <= p.y() && p.y() <= ey) || (ey <= p.y() && p.y() <= by))
      if (Utilities::floatEquality(mBegin.x(),p.x()))
        return true;
    return false;
    /*
    return mBegin.y() <= p.y() && p.y() <= mEnd.y() &&
           Utilities::floatEquality(mBegin.x(),p.x());
    */
  }
}

GeometryUtilities::Point GeometryUtilities::LineSegment::closestPointOn(const GeometryUtilities::Point &p) const
{
  GeometryUtilities::Point diff = p-mBegin;
  GeometryUtilities::Point dir = mEnd-mBegin;
  qreal dot1 = diff.dot(dir);
  if (dot1 <= 0.0f)
    return mBegin;

  qreal dot2 = dir.dot(dir);
  if (dot2 <= dot1)
    return mEnd;

  qreal t=dot1/dot2;
  return mBegin + (dir * t);
}

bool GeometryUtilities::LineSegment::operator==
(const GeometryUtilities::LineSegment& rhs) const
{
  return (mBegin == rhs.begin() && mEnd == rhs.end()) ||
         (mBegin == rhs.end() && mEnd == rhs.begin());
}

GeometryUtilities::LineSegment GeometryUtilities::LineSegment::toPerpendicularFromBegin(qreal offset, qreal magnitude) const
{
  Point dir(mEnd-mBegin);
  dir.normalize();
  Point perpDir(-dir.y(), dir.x());
  perpDir.normalize();
  Point offsetPt(mBegin+(dir*offset));
  return LineSegment(offsetPt-(perpDir*magnitude/2.0), offsetPt+(perpDir*magnitude/2.0));
}

GeometryUtilities::LineSegment GeometryUtilities::LineSegment::toPerpendicularFromEnd(qreal offset, qreal magnitude) const
{
  Point dir(mEnd-mBegin);
  dir.normalize();
  Point perpDir(-dir.y(), dir.x());
  perpDir.normalize();
  Point offsetPt(mEnd+(dir*offset));
  return LineSegment(offsetPt-(perpDir*magnitude/2.0), offsetPt+(perpDir*magnitude/2.0));
}

GeometryUtilities::LineSegment GeometryUtilities::LineSegment::toOffset(qreal offset) const
{
  return LineSegment(toPerpendicularFromBegin(0, offset*2).end(),
                     toPerpendicularFromEnd(0, offset*2).end());
}
